#include "Parser.h"


Parser::Parser(string& fileLocation){
	this->fileLocation = fileLocation;
	this->a = new Analyzer();
	this->ip = new InputLine();
	this->numOfLines = 1;
	this->rows = new map<int,string>; 
	this->parsedLines = new map<int,vector<Token>>;
}

//DTOR
Parser::~Parser(){
	delete(a);
	a=NULL;
	delete(ip);
	ip=NULL;
	delete(rows);
	rows=NULL;
	delete(parsedLines);
	parsedLines=NULL;
};

//Copy CTOR
Parser::Parser(const Parser& p) { 
	this->numOfLines = p.numOfLines;
	this->fileLocation = p.fileLocation;
	Analyzer* new_a = new Analyzer();
	new_a = p.a;
	delete(this->a);
	this->a = new_a;
	
	InputLine* new_ip = new InputLine();
	new_ip = p.ip;
	delete(this->ip);
	this->ip = new_ip;

	this->rows = new map<int,string>;
	map<int,string>::iterator it;
	for(it = p.rows->begin();it!=p.rows->end();it++)
		this->rows->insert(pair<int,string>((*it).first,(*it).second));
}

//Assignment overloading
const Parser& Parser::operator=(const Parser& p){
	if (this!=&p) { 
		this->assign(p);
	}
		return *this;
}


const int Parser::getNumOfLines(){
	return this->numOfLines;
}
const Parser& Parser::assign(const Parser& p){
	
	this->numOfLines = p.numOfLines;
	this->fileLocation = p.fileLocation;
	Analyzer* new_a = new Analyzer();
	new_a = p.a;
	delete(this->a);
	this->a = new_a;
	
	InputLine* new_ip = new InputLine();
	new_ip = p.ip;
	delete(this->ip);
	this->ip = new_ip;

	map<int,string>* new_map = new map<int,string>;
	map<int,string>::iterator it;
	for(it = p.rows->begin();it!=p.rows->end();it++)
		new_map->insert(pair<int,string>((*it).first,(*it).second));
	delete(this->rows);
	this->rows = new_map;
	return *this;
}






void Parser::parse() { 
	int sumOfOverAllTokens = 0;
	ifstream ifs;
	string lineStr = "";
	//char c;
	ifs.open (this->fileLocation);
	if (ifs.is_open()) { 
		//Start filling the rows database
		cout<<"******************************************************************************"<<endl;
		cout<<"Compiler: getting lines from file"<<endl;
		cout<<"******************************************************************************"<<endl;
		while (!ifs.eof())
		{	
				getline(ifs,lineStr);
				//insert it
				this->rows->insert(pair<int,string>(numOfLines,lineStr));
				if (!ifs.eof())
				Parser::numOfLines++;
				lineStr="";
		}
		cout<<"******************************************************************************"<<endl;
		cout<<"Compiler: completed parsing phase"<<endl;
		cout<<"******************************************************************************"<<endl;
		cout<<"There are "<<Parser::getNumOfLines()<<" rows in the file"<<endl;
		cout<<"******************************************************************************"<<endl;
		ifs.close();
	

		//Parsing completed-now start tokenizing the rows;
		map<int,string>::iterator it;
		cout<<"******************************************************************************"<<endl;
		cout<<"Compiler: Now tokenizing the rows"<<endl;
		cout<<"******************************************************************************"<<endl;
		int rowNumber = 1;
		for (it=rows->begin();it!=rows->end();it++) {
			vector<Token> vec;
			vec = this->ip->TokenizeLine((*it).first,(*it).second);
			//insert the tokened line
			this->parsedLines->insert(pair<int,vector<Token>>((*it).first,vec));
			//Print the tokens
			int numOfTokens = vec.size();
			sumOfOverAllTokens+=numOfTokens;
			cout<<"There are "<<numOfTokens<<" tokens in line: "<<rowNumber<<endl;
			rowNumber++;	
		}
		cout<<"******************************************************************************"<<endl;
		cout<<"There are "<<sumOfOverAllTokens<<" tokens in the file"<<endl;
		cout<<"******************************************************************************"<<endl;
		cout<<"Compiler: Finished tokenizing the rows"<<endl;
		cout<<"******************************************************************************"<<endl;

		//Tokenizing completed-now start analyzing the tokens;
		cout<<"Compiler: Now analyzing the rows, reporting any errors"<<endl;
		cout<<"******************************************************************************"<<endl;

		this->a->analyze(this->parsedLines);
		vector<string> errors =( this->a->getErrors());
		vector<string>::iterator itErr;
		for(itErr=errors.begin();itErr!=errors.end();itErr++)
			cout<<(*itErr)<<endl;	 
		//print funcs
		cout<<"******************************************************************************"<<endl;
		cout<<"Functions in the program are: "<<endl;
		cout<<"******************************************************************************"<<endl;

		map<string,int>* funcVec =this->a->getFunctions();
		map<string,int>::iterator itFunc;
		for(itFunc=funcVec->begin();itFunc!=funcVec->end();itFunc++){
			cout<<"Function "+(*itFunc).first+" declared in line: "+Misc::intToString((*itFunc).second)<<endl;
		}
		// print vars
		cout<<"******************************************************************************"<<endl;
		cout<<"Variables in the program are: "<<endl;
		cout<<"******************************************************************************"<<endl;

		map<string,int>* varVec =this->a->getVariables();
		map<string,string>* typesOfVars = this->a->getTypesOfVars();
		map<string,int>::iterator itVars;
		for(itVars=varVec->begin();itVars!=varVec->end();itVars++){
			cout<<
				typesOfVars->find((*itVars).first)->second +" "
				+
				(*itVars).first+" declared in line: "+
				Misc::intToString((*itVars).second)<<endl;
		}

	}
	else cout<<"Unable to open file"<<endl<<"Please provide a valid file path"<<endl;
 }






